added SSCLI 1.0
[windows-sources.git] / shared source / sscli20 / tools / nmake / action.cpp
blob1a48e9ebf5c12ef497d48363052dc8ce08014871
1 // ==++==
2 //
3 //
4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
5 //
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
10 //
11 // You must not remove this notice, or any other, from this software.
12 //
14 // ==--==
15 // ACTION.C -- routines called by the parser
17 // Purpose:
18 // This module contains the routines called during parsing of a makefile.
20 #include "precomp.h"
21 #ifdef _MSC_VER
22 #pragma hdrstop
23 #endif
25 void startNameList(void);
26 void makeRule(STRINGLIST *, BOOL fBatch);
27 void makeTarget(char*, BOOL, BUILDBLOCK**);
28 void appendPseudoTargetList(STRINGLIST**, STRINGLIST*);
29 void clearSuffixes(void);
30 BOOL doSpecial(char*);
31 BUILDLIST * makeBuildList(BUILDBLOCK *);
32 char * nextComponent(char **);
34 // created by endNameList() & freed by assignBuildCommands(). In use because
35 // although global 'list' has this list is used by too many routines and the
36 // complete sequence of actions on 'list' is unknown
38 STRINGLIST * targetList; // corr to a dependency block
41 // makeName -- create copy of a name seen by lexer
43 // Purpose:
44 // Create a copy of a macro or 1st name in a target/dependency list. It also
45 // does the groundwork for expansion of macros in name and saves values.
47 // Assumes: That the lexical routines save the token in buf
49 // Modifies Globals:
50 // name -- the pointer to the copy created, gets allocated memory
51 // macros -- the list of macro values in name. Used later by startNameList()
52 // to expand macros in name and get expanded target name.
54 // Uses Globals:
55 // buf -- the lexical routines return a token in this
57 // Notes:
58 // The token in buf could be part of a macrodefinition or a target list. The
59 // next token determines if it is a macrodefn or a targetlist we are parsing.
60 // The next token would overwrite the current token and so it is saved in name.
62 void
63 makeName()
65 findMacroValues(buf, &macros, NULL, NULL, 0, 0, 0);
66 name = makeString(buf);
71 void
72 addItemToList()
74 STRINGLIST *p; // from lexer
75 STRINGLIST *NewList;
77 if (name) {
78 SET(actionFlags, A_TARGET);
79 startNameList();
80 name = NULL;
82 if (ON(actionFlags, A_TARGET)) {
83 if (isRule(buf)) {
84 if (ON(actionFlags, A_RULE))
85 makeError(currentLine, TOO_MANY_RULE_NAMES);
86 makeError(currentLine, MIXED_RULES);
89 p = makeNewStrListElement();
90 if (ON(actionFlags, A_STRING)) { // we collect macros
91 p->text = string; // for dependents &
92 string = NULL; // build lines for
93 } else // non-implicit rules
94 p->text = makeString(buf);
96 NewList = p; // build lines for
97 if (OFF(actionFlags, A_RULE) // rules get expanded
98 || ON(actionFlags, A_TARGET)) // after entire make-
100 findMacroValues(p->text, &macros, NULL, NULL, 0, 0, 0); // file parsed
103 if (ON(actionFlags, A_TARGET)) {
104 p = macros;
105 expandFileNames("$", &NewList, &macros);
106 expandFileNames("*?", &NewList, NULL);
107 while ((macros = p)) {
108 p = p->next;
109 FREE_STRINGLIST(macros);
113 appendItem(&list, NewList);
117 // startNameList -- puts in the first element into list
119 // Scope: Local.
121 // Purpose: Puts in the first name seen into a list
123 // Errors/Warnings: TARGET_MACRO_IS_NULL -- if the macro used as a target expands to null
125 // Assumes:
126 // The global 'list' is originally a null list, & the global 'macro' points to
127 // a list of values used for expanding the macros in global 'name'.
129 // Modifies Globals:
130 // list -- the list of names; set to contain the first name here or to a
131 // list of values if 'name' contains a macro invocation.
132 // macros -- the list of values reqd for macro expansion; the list is
133 // freed and macros is made NULL
134 // currentFlags -- the flags for current target; set to global flags
135 // actionFlags -- determine actions to be done; if the name is a rule then set
136 // the rule bit
138 // Uses Globals:
139 // name -- the first name seen in a list of names.
140 // flags -- the global flags setup by the options specified
141 // actionFlags -- if handling targets then no error as we have > 1 target
143 // Notes:
144 // If there is more than one target then actionFlags has A_TARGET flag set and
145 // startNameList() is called from addItemToList. In this case don't flag error.
147 void
148 startNameList()
150 STRINGLIST *p;
152 currentFlags = flags; // set flags for cur target
153 p = makeNewStrListElement();
154 p->text = name;
155 list = p; // list contains name
156 p = macros;
157 expandFileNames("$", &list, &macros); // expand macros in name
158 expandFileNames("*?", &list, NULL); // expand wildcards
159 while ((macros = p)) { // free macro list
160 p = p->next;
161 FREE_STRINGLIST(macros);
163 if (!list && OFF(actionFlags, A_TARGET))
164 makeError(line, TARGET_MACRO_IS_NULL, name); // target null & 1 target
166 if (list && isRule(list->text))
167 SET(actionFlags, A_RULE);
171 // endNameList -- semantic actions when a list is fully seen
173 // Purpose:
174 // When the parser has seen an entire list then it needs to do some semantic
175 // actions. It calls endNameList() to do these actions. The action depends on
176 // the values in certain globals.
178 // Modifies Globals: actionFlags --
180 // Uses Globals:
181 // name -- The first element seen (if non null)
182 // actionFlags -- The flag determining semantic & data structure actions
183 // buf -- The delimiter seen after list
184 // list -- The list of elements seen
186 void
187 endNameList()
189 if (name) { // if only one name to left of :
190 startNameList(); // it hasn't been put in list yet
191 name = NULL;
192 } else
193 CLEAR(actionFlags, A_TARGET); // clear target flag
195 if (buf[1])
196 SET(currentFlags, F2_DOUBLECOLON); // so addItemToList()
198 if (!list) // won't expand names
199 makeError(currentLine, SYNTAX_NO_TARGET_NAME); // of dependents
201 if (ON(actionFlags, A_RULE)) {
202 BOOL fBatch;
203 // A rule with a doublecolon on the dependency line
204 // is a "batch rule", i.e., a rule that applies the
205 // command block in batch mode for all affected
206 // dependents.
207 fBatch = !!(ON(currentFlags, F2_DOUBLECOLON));
208 makeRule(list, fBatch);
209 FREE_STRINGLIST(list);
211 else if (!(list->next) && doSpecial(list->text)) { // special pseudotarget ...
212 FREE(list->text); // don't need ".SUFFIXES" etc
213 FREE_STRINGLIST(list);
215 else // regular target
216 targetList = list;
218 list = NULL;
219 // We are now looking for a dependent
220 SET(actionFlags, A_DEPENDENT);
224 BOOL
225 doSpecial(
226 char *s)
228 BOOL status = FALSE;
230 if (!_tcsicmp(s, silent)) {
231 SET(actionFlags, A_SILENT);
232 setFlags('s', TRUE);
233 status = TRUE;
236 if (!_tcsicmp(s, ignore)) {
237 SET(actionFlags, A_IGNORE);
238 setFlags('i', TRUE);
239 status = TRUE;
241 else if (!_tcscmp(s, suffixes)) {
242 SET(actionFlags, A_SUFFIX);
243 status = TRUE;
245 else if (!_tcscmp(s, precious)) {
246 SET(actionFlags, A_PRECIOUS);
247 status = TRUE;
249 return(status);
253 void
254 expandFileNames(
255 char *string,
256 STRINGLIST **sourceList,
257 STRINGLIST **macroList
260 char *s,
261 *t = NULL;
262 STRINGLIST *p; // Main list pointer
263 STRINGLIST *pNew, // Pointer to new list
264 *pBack; // Pointer to one element back
265 char *saveText = NULL;
267 for (pBack = NULL, p = *sourceList; p;) {
269 // If no expand-character is found, continue to next list element.
270 if (!_tcspbrk(p->text, string)) {
271 pBack = p;
272 p = pBack->next;
273 continue;
276 // Either expand macros or wildcards.
277 if (*string == '$') {
278 t = expandMacros(p->text, macroList);
279 FREE(p->text);
280 } else {
282 // If the wildcard string does not expand to anything, go to
283 // next list elment. Do not remove p from the original list
284 // else we must check for null elsewhere.
286 // -- do not attempt to expand wildcards that
287 // occur in inference rules
289 if (isRule(p->text) || (pNew = expandWildCards(p->text)) == NULL) {
290 pBack = p;
291 p = pBack->next;
292 continue;
294 saveText = p->text;
297 // At this point we have a list of expanded names to replace p with.
298 if (pBack) {
299 pBack->next = p->next;
300 FREE_STRINGLIST(p);
301 p = pBack->next;
302 } else {
303 *sourceList = p->next;
304 FREE_STRINGLIST(p);
305 p = *sourceList;
308 if (*string == '$') { // if expanding macros
309 char *str = t;
310 if ((s = nextComponent(&str))) {
311 do { // put expanded names
312 pNew = makeNewStrListElement(); // at front of list
313 pNew->text = makeString(s); // so we won't try to
314 prependItem(sourceList, pNew); // re-expand them
315 if (!pBack)
316 pBack = pNew;
317 } while ((s = nextComponent(&str)));
319 FREE(t);
320 continue;
322 else if (pNew) { // if matches for * ?
323 if (!pBack)
324 for (pBack = pNew; pBack->next; pBack = pBack->next)
326 appendItem(&pNew, *sourceList); // put at front of old list
327 *sourceList = pNew;
329 FREE(saveText);
334 // nextComponent - returns next component from expanded name
336 // Scope: Local (used by expandFilenames)
338 // Purpose:
339 // Given a target string (target with macros expanded) this function returns a
340 // name component. Previously _tcstok(s, " \t") was used but with the advent of
341 // quoted filenames this is no good.
343 // Input: szExpStr - the target name with macros expanded
345 // Output: Returns pointer to next Component; NULL means no more components left.
347 // Assumes: That that two quoted strings are seperated by whitespace.
349 char *
350 nextComponent(
351 char **szExpStr
354 char *t, *next;
356 t = *szExpStr;
358 while (WHITESPACE(*t))
359 t++;
361 next = t;
362 if (!*t)
363 return(NULL);
365 if (*t == '"') {
366 for (; *++t && *t != '"';)
368 } else {
369 for (; *t && *t != ' ' && *t != '\t'; t++)
373 if (WHITESPACE(*t)) {
374 *t = '\0';
375 } else if (*t == '"') {
376 t++;
377 if(*t=='\0') t--; // If this is the end of the string, backup a byte, so we don't go past next time
378 else *t = '\0'; // else stop here for this time.
379 } else if (!*t) {
380 // If at end of string then backup a byte so that next time we don't go past
381 t--;
384 *szExpStr = t+1;
385 return(next);
389 // append dependents to existing ones (if any)
390 void
391 assignDependents()
393 const char *which = NULL;
395 if (ON(actionFlags, A_DEPENDENT))
396 CLEAR(actionFlags, A_DEPENDENT);
398 if (ON(actionFlags, A_RULE)) {
399 if (list)
400 makeError(currentLine, DEPENDENTS_ON_RULE);
402 else if (ON(actionFlags, A_SILENT) || ON(actionFlags, A_IGNORE)) {
403 if (list) {
404 if (ON(actionFlags, A_SILENT))
405 which = silent;
406 else if (ON(actionFlags, A_IGNORE))
407 which = ignore;
408 makeError(currentLine, DEPS_ON_PSEUDO, which);
411 else if (ON(actionFlags, A_SUFFIX)) {
412 if (!list)
413 clearSuffixes();
414 else
415 appendPseudoTargetList(&dotSuffixList, list);
417 else if (ON(actionFlags, A_PRECIOUS)) {
418 if (list)
419 appendPseudoTargetList(&dotPreciousList, list);
421 else {
422 block = makeNewBuildBlock();
423 block->dependents = list;
424 block->dependentMacros = macros;
426 list = NULL;
427 macros = NULL;
428 SET(actionFlags, A_STRING); // expecting build cmd
431 void
432 assignBuildCommands()
434 BOOL okToFreeList = TRUE;
435 BOOL fFirstTarg = (BOOL)TRUE;
436 STRINGLIST *p;
437 const char *which = NULL;
439 if (ON(actionFlags, A_RULE)) // no macros found yet for inference rules
440 rules->buildCommands = list;
441 else if (ON(actionFlags, A_SILENT) ||
442 ON(actionFlags, A_IGNORE) ||
443 ON(actionFlags, A_PRECIOUS) ||
444 ON(actionFlags, A_SUFFIX)
446 if (list) {
447 if (ON(actionFlags, A_SILENT))
448 which = silent;
449 else if (ON(actionFlags, A_IGNORE))
450 which = ignore;
451 else if (ON(actionFlags, A_PRECIOUS))
452 which = precious;
453 else if (ON(actionFlags, A_SUFFIX))
454 which = suffixes;
455 makeError(currentLine, CMDS_ON_PSEUDO, which);
457 } else {
458 block->buildCommands = list;
459 block->buildMacros = macros;
460 block->flags = currentFlags;
461 while ((p = targetList)) { // make a struct for each targ
462 if (doSpecial(p->text)) // in list, freeing list when
463 makeError(currentLine, MIXED_TARGETS);
464 makeTarget(p->text, fFirstTarg, &block); // done, don't free name
465 if (!makeTargets) { // field -- it's still in use
466 makeTargets = p; // if no targs given on cmdlin
467 okToFreeList = FALSE; // put first target(s) from
468 } // mkfile in makeTargets list
469 targetList = p->next; // (makeTargets defined in
470 if (okToFreeList) // nmake.c)
471 FREE_STRINGLIST(p);
472 if (fFirstTarg)
473 fFirstTarg = (BOOL)FALSE;
476 targetList = NULL;
477 list = NULL;
478 macros = NULL;
479 block = NULL;
480 actionFlags = 0;
483 // makeMacro -- define macro with name and string taken from global variables
485 // Modifies:
486 // fInheritUserEnv set to TRUE
488 // Notes:
489 // Calls putMacro() to place expanded Macros in the NMAKE table. By setting
490 // fInheritUserEnv those definitions that change Environment variables are
491 // inherited by the environment.
493 void
494 makeMacro()
496 STRINGLIST *q;
497 char *t;
499 if (_tcschr(name, '$')) { // expand name
500 q = macros;
501 t = expandMacros(name, &macros); // name holds result
502 if (!*t) // error if macro to left of = is undefined
503 makeError(currentLine, SYNTAX_NO_MACRO_NAME);
504 while ((macros = q)) {
505 q = q->next;
506 FREE_STRINGLIST(macros);
508 FREE(name);
509 name = t;
512 for (t = name; *t && MACRO_CHAR(*t); t = _tcsinc (t)) // Check for illegal chars
515 if (*t)
516 makeError(currentLine, SYNTAX_BAD_CHAR, *t);
518 fInheritUserEnv = (BOOL)TRUE;
520 // Put Env Var in Env & macros in table.
522 if (!putMacro(name, string, 0)) {
523 FREE(name);
524 FREE(string);
526 name = string = NULL;
530 // defineMacro -- check macro's syntax for illegal chars., then define it
532 // actions: check all of macro's characters
533 // if one's bad and it's an environment macro, bag it
534 // else flag error
535 // call putMacro to do the real work
537 // can't use macro invocation to left of = in macro def from commandline
538 // it doesn't make sense to do that, because we're not in a makefile
539 // the only way to get a comment char into the makefile w/o having it really
540 // mark a comment is to define a macro A=# on the command line
542 BOOL
543 defineMacro(
544 char *s, // commandline or env definitions
545 char *t,
546 UCHAR flags
549 char *u;
551 for (u = s; *u && MACRO_CHAR(*u); u = _tcsinc(u)) // check for illegal
553 if (*u) {
554 if (ON(flags, M_ENVIRONMENT_DEF)) { // ignore bad macros
555 return(FALSE);
557 makeError(currentLine, SYNTAX_BAD_CHAR, *u); // chars, bad syntax
559 return(putMacro(s, t, flags)); // put macro in table
563 // putMacro - Put the macro definition into the Macro Table / Environmnet
565 // Scope:
566 // Global.
568 // Purpose:
569 // putMacro() inserts a macro definition into NMAKE's macro table and also into
570 // the environment. If a macro name is also an environment variable than its
571 // value is inherited into the environment. While replacing older values by new
572 // values NMAKE needs to follow the precedence of macro definitions which is
573 // as per the notes below.
575 // Input:
576 // name - Name of the macro
577 // value - Value of the macro
578 // flags - Flags determining Precedence of Macro definitions (see Notes)
580 // Output:
582 // Errors/Warnings:
583 // OUT_OF_ENV_SPACE - If putenv() returns failure in adding to the environment.
585 // Assumes:
586 // Whatever it assumes
588 // Modifies Globals:
589 // fInheritUserEnv - Set to False.
591 // Uses Globals:
592 // fInheritUserEnv - If True then Inherit definition to the Environment.
593 // gFlags - Global Options Flag. If -e specified then Environment Vars
594 // take precedence.
595 // macroTable - NMAKE's internal table of Macro Definitions.
597 // Notes:
598 // 1> If the same macro is defined in more than one place then NMAKE uses the
599 // following order of Precedence (highest to lowest) --
601 // -1- Command line definitions
602 // -2- Description file/Include file definitions
603 // -3- Environment definitions
604 // -4- TOOLS.INI definitions
605 // -5- Predefined Values (e.g. for CC, AS, BC, RC)
606 // If -e option is specified then -3- precedes -2-.
608 // 2> Check if the macro already exists in the Macro Table. If the macro is not
609 // redefinable (use order of precedence) then return. Make a new string
610 // element to hold macro's new value. If the macro does not exist then create
611 // new entry in the Macro table. Set Macro's flag to be union of Old and new
612 // values. Add the new value to macro's value entry. If a new macro then add
613 // it to the macro table. Test for Cyclic definitions.
615 BOOL
616 putMacro(
617 char *name,
618 char *value,
619 UCHAR flags
622 MACRODEF *p;
623 STRINGLIST *q;
624 BOOL defined = FALSE;
625 BOOL fSyntax = TRUE;
627 // Convert path separators to the native path separator.
628 // Do that with a copy of the original string so we don't change
629 // the original.
630 value = makeString(value);
631 #if PLATFORM_UNIX
632 char *tmp = value;
633 while ((tmp = FindFirstPathSeparator(tmp))) {
634 *tmp++ = PATH_SEPARATOR_CHAR;
636 #endif
639 if (ON(flags, M_NON_RESETTABLE)) {
640 if (*value)
641 if ((putEnvStr(name,removeMacros(value)) == -1))
642 makeError(currentLine, OUT_OF_ENV_SPACE);
643 } else
644 if (fInheritUserEnv &&
645 OFF(gFlags, F1_USE_ENVIRON_VARS) &&
646 getenv(name)
648 if ((p = findMacro(name))) { // don't let user
649 if (CANT_REDEFINE(p)) // redefine cmdline
650 return(FALSE); // macros, MAKE, etc.
652 if ((putEnvStr(name,removeMacros(value)) == -1))
653 makeError(currentLine, OUT_OF_ENV_SPACE);
656 fInheritUserEnv = (BOOL)FALSE;
657 if ((p = findMacro(name))) { // don't let user
658 if (CANT_REDEFINE(p)) // redefine cmdline
659 return(FALSE); // macros, MAKE, etc.
662 q = makeNewStrListElement();
663 q->text = value;
665 if (!p) {
666 p = makeNewMacro();
667 p->name = name;
668 assert(p->flags == 0);
669 assert(p->values == NULL);
670 } else
671 defined = TRUE;
673 p->flags &= ~M_UNDEFINED; // Is no longer undefined
674 p->flags |= flags; // Set flags to union of old and new
675 prependItem((STRINGLIST**)&(p->values), (STRINGLIST*)q);
676 if (!defined)
677 insertMacro((STRINGLIST*)p);
679 if (OFF(flags, M_LITERAL) && _tcschr(value, '$')) { // Check for cyclic Macro Definitions
680 SET(p->flags, M_EXPANDING_THIS_ONE);
681 // NULL -> don't build list
682 fSyntax = findMacroValues(value, NULL, NULL, name, 1, 0, flags);
683 CLEAR(p->flags, M_EXPANDING_THIS_ONE);
686 if (!fSyntax) {
687 p->values = NULL;
688 p->flags |= M_UNDEFINED;
689 //return(FALSE);
690 // return TRUE since p has been added to the macro table
691 // Otherwise the caller may free name and value leaving
692 // dangling pointers in the macro table.
693 return(TRUE);
695 return(TRUE);
699 // makeRule -- makes an inference rule
701 // Scope:
702 // Local
704 // Purpose:
705 // Allocates space for an inference rule and adds rule to the beginning of the
706 // doubly linked inference rule list. The name of the rule is also added.
708 // Input:
709 // rule -- The name of the inference rule
710 // fBatch -- True if command block should be executed in batch mode
712 // Output:
714 // Errors/Warnings:
716 // Assumes:
718 // Modifies Globals:
719 // rules -- The doubly linked inference rule list to which the rule is added
721 // Uses Globals:
723 // Notes:
724 // The syntax of an inference rule is --
726 // {frompath}.fromext{topath}.toext: # Name of the inference rule
727 // command ... # command block of the inference rule
729 void
730 makeRule(
731 STRINGLIST *rule,
732 BOOL fBatch
735 RULELIST *rList;
737 rList = makeNewRule();
738 rList->name = rule->text;
740 #if PLATFORM_UNIX
741 // Convert path separators to the native path separator.
742 char *tmp = rList->name;
743 while ((tmp = FindFirstPathSeparator(tmp))) {
744 *tmp++ = PATH_SEPARATOR_CHAR;
746 #endif // PLATFORM_UNIX
748 rList->fBatch = fBatch;
749 prependItem((STRINGLIST**)&rules, (STRINGLIST*)rList);
750 if (rList->next)
751 rList->next->back = rList;
755 // makeTarget -- add target to targetTable
757 // actions: if no block defined, create one and initialize it
758 // make new build list entry for this target
759 // if the target's already in the table,
760 // flag error if : and :: mixed
761 // else add new buildlist object to target's current buildlist
762 // else allocate new object, initialize it, and stick it in table
764 void
765 makeTarget(
766 char *s,
767 BOOL firstTarg,
768 BUILDBLOCK **block
771 BUILDLIST *build;
772 MAKEOBJECT *object;
774 if (!*block)
775 *block = makeNewBuildBlock();
777 if (firstTarg) {
778 build = makeNewBldListElement();
779 build->buildBlock = *block;
780 } else
781 build = makeBuildList(*block);
783 if ((object = findTarget(s))) {
784 if (ON(object->flags2, F2_DOUBLECOLON) != ON(currentFlags, F2_DOUBLECOLON))
785 makeError(currentLine, MIXED_SEPARATORS);
786 appendItem((STRINGLIST**)&(object->buildList), (STRINGLIST*)build);
787 FREE(s);
788 } else {
789 build->next = NULL;
790 object = makeNewObject();
791 object->name = s;
792 object->buildList = build;
793 object->flags2 = currentFlags;
794 prependItem((STRINGLIST**)targetTable+hash(s, MAXTARGET, (BOOL)TRUE),
795 (STRINGLIST*)object);
800 void
801 clearSuffixes()
803 STRINGLIST *p;
805 while ((p = dotSuffixList)) {
806 dotSuffixList = dotSuffixList->next;
807 FREE(p->text);
808 FREE_STRINGLIST(p);
813 void
814 appendPseudoTargetList(
815 STRINGLIST **pseudo,
816 STRINGLIST *list
819 STRINGLIST *p, *q, *r;
820 char *t, *u;
822 while ((p = list)) {
823 if (!_tcschr(p->text, '$')) {
824 list = list->next;
825 p->next = NULL;
826 appendItem(pseudo, p);
827 } else {
828 r = macros;
829 t = expandMacros(p->text, &macros);
830 while (r != macros) {
831 q = r->next;
832 FREE_STRINGLIST(r);
833 r = q;
835 for (u = _tcstok(t, " \t"); u; u = _tcstok(NULL, " \t")) {
836 q = makeNewStrListElement();
837 q->text = makeString(u);
838 appendItem(pseudo, q);
840 FREE(t);
841 FREE(p->text);
842 list = list->next;
843 FREE_STRINGLIST(p);
848 // putEnvStr -- Extends putenv() standard function
850 // Purpose:
851 // Library function putenv() expects one string argument of the form
852 // "NAME=value"
853 // Most of the times when putenv() is to be used we have two strings
854 // name -- of the variable to add to the environment, and
855 // value -- to be set
856 // putEnvStr takes these 2 parameters and calls putenv with the reqd
857 // format
859 // Input:
860 // name -- of var to add to the env
861 // value -- reqd to be set
863 // Output:
864 // Same as putenv()
867 putEnvStr(
868 char *name,
869 char *value
872 BOOL b = SetEnvironmentVariableA(name, value);
874 return (b) ? 0 : -1;
878 // makeBuildList -- takes a build block and copies into a buildlist
880 // Purpose:
881 // Routine creates a copy of a buildlist and returns a pointer to a copy.
882 // When multiple targets have the same description block then there is a
883 // need for each of them to get seperate build blocks. makeBuildList()
884 // helps achieve this by creating a copy for each target.
886 // Input:
887 // bBlock -- the build block whose copy is to be added to a build block
889 // Output:
890 // Returns a pointer to the copy of buildlist it creates
892 BUILDLIST *
893 makeBuildList(
894 BUILDBLOCK *bBlock
897 BUILDLIST *tList = makeNewBldListElement();
898 BUILDBLOCK *tBlock = makeNewBuildBlock();
900 tBlock->dependents = bBlock->dependents;
901 tBlock->dependentMacros = bBlock->dependentMacros;
902 tBlock->buildCommands = bBlock->buildCommands;
903 tBlock->buildMacros = bBlock->buildMacros;
904 tBlock->flags = bBlock->flags;
905 tBlock->dateTime = bBlock->dateTime;
907 tList->buildBlock = tBlock;
908 return(tList);